﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using MathLib;

namespace Demog {
    public partial class SimulatedPopulation : Form {


        private int period; //Временной интервал между прогнозированиями 
        private int groupCount; // Число рассматриваемых групп
        private int periodCount; // Число периодов прогнозирования

        private double Vnu; //Относительное среднекв. отклонение вых.шумов
        private double  Utf; //Относительное среднекв. отклонение рождаемости
        private double Utm; //Относительное среднекв. отклонение передвижки
        private bool fullind; //Индекс наблюдению популяции: true - Наблюдается общая численность, false - по возрастам
        private bool estind;
        private Matrix[] x; //прогноз, полученный без фильтрации
        private Matrix[] xx; //прогноз, полученный с фильтрацией

        private GeneratedPopulation genPop; // Сгенерированная модель популяции

        public SimulatedPopulation(GeneratedPopulation genPop) {
            InitializeComponent();
            this.genPop = genPop;
            this.groupCount = AppParameters.Params.GroupCount;
            this.period = AppParameters.LifeLength / AppParameters.Params.GroupCount;
        }


        private void PrintMatrix(DataGridView dgv, Matrix m) {
            DataTable table = CreateTable(m.NoRows, m.NoCols);
            for (int i = 0; i < m.NoRows; i++) {
                DataRow dr = table.Rows[i];
                for (int j = 0; j < m.NoCols; j++)
                    dr[j] = Math.Round(m[i, j], 5);
            }

            dgv.DataSource = table;
        }

        private void PrintMatrixRound(DataGridView dgv, Matrix m) {
            DataTable table = CreateTable(m.NoRows, m.NoCols);
            for (int i = 0; i < m.NoRows; i++) {
                DataRow dr = table.Rows[i];
                for (int j = 0; j < m.NoCols; j++)
                    dr[j] = Math.Round(m[i, j]);
            }

            dgv.DataSource = table;
        }

        private DataTable CreateTable(int rows, int columns) {
            DataTable t = new DataTable();
            for (int j = 0; j < columns; j++)
                t.Columns.Add();
            for (int i = 0; i < rows; i++)
                t.Rows.Add();

            return t;
        }

        private void SimulatedPopulation_Shown(object sender, EventArgs e) {
            if (genPop.populations.Length == 0)
                return;

            if (genPop.matrixMainValue < 1) lbMatrixStability.Text = "Популяция стремится к нулевому распределению";
            if (genPop.matrixMainValue > 1) lbMatrixStability.Text = "Популяция экспоненциально возрастает";
            if (genPop.matrixMainValue == 1) lbMatrixStability.Text = "Популяция ассимпт. стремится к предельному состоянию";
           
            DataTable dt = new DataTable();
            for (int i = 0; i < genPop.populations.Length; i++) {
                dt.Columns.Add(i.ToString() + "-й период");
            }

            int rowCount = genPop.populations.Max(m => m.NoRows);

            for (int i = 0; i < rowCount; i++) {
                DataRow dr = dt.Rows.Add();
                for (int j = 0; j < genPop.populations.Length; j++)
                    if (i < genPop.populations[j].NoRows)
                        dr[j] = Math.Round(genPop.populations[j][i, 0]);
            }

            dgvPopulations.DataSource = dt;

            tbperiod.Text = period.ToString();
            tbpopCount.Text = genPop.populations.Length.ToString();

            PrintMatrix(dgvpopMatrixes, genPop.populationMatrixes[0]);
        }




        private void bPrediction_Click(object sender, EventArgs e) {
            periodCount = int.Parse(tbperiodCount.Text); // Считать период прогнозирования
            if (periodCount > genPop.populations.Length) {
                MessageBox.Show("Период прогнозирования не должен превышать число векторов наблюдения", "Внимание", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            Vnu = double.Parse(tbVnu.Text); //Считать среднеквадратическое отклонения вых.шумов
            Utf = double.Parse(tbUtf.Text); //Считать среднеквадратическое отклонения вх.шумов
            Utm = double.Parse(tbUtm.Text);
            fullind = chbFull.Checked;
            estind = chbEstimate.Checked;

            DemogFilterAlg df = new DemogFilterAlg(periodCount, genPop, Vnu,Utf,Utm, fullind,estind);

            Matrix[] NuFull = GenerationUtils.GenerateNoise(groupCount, genPop.populations, Vnu, true);
            Matrix[] Nu = GenerationUtils.GenerateNoise(groupCount, genPop.populations, Vnu, fullind);
            Matrix[] MatrixNu = GenerationUtils.GenerateMatrixNoise(groupCount, genPop.populationMatrixes, Utf, Utm);

            this.x = df.Solve(NuFull, MatrixNu);
            this.xx = df.SolveWithFilter(Nu, MatrixNu);

            PrintMatrixRound(dgvPrediction, x[periodCount-1]);
            PrintMatrixRound(dgvFilter, xx[periodCount-1]);
            PrintMatrixRound(dgvReal, genPop.populations[periodCount-1]);

        }

        private void label9_Click(object sender, EventArgs e) {

        }

        private void bGraph_Click(object sender, EventArgs e) {
            // Matrix z = this.populations[periodCount];

            if ((object)x == null || (object)xx == null || (object)genPop.populations == null)
                return;
            ChartForm graph = new ChartForm(x, xx, genPop.populations);
            graph.ShowDialog();

        }



        private void bFind_Click(object sender, EventArgs e) {

            DemogFilterAlg df = new DemogFilterAlg(periodCount, genPop, Vnu, Utf, Utm, fullind,estind);

            int expCount = int.Parse(tbExpCount.Text);
            double s1=0;
            double s2=0;

            Matrix disp = new Matrix(groupCount, 1);

      //      disp = GenerationUtils.GenerateDisp(groupCount,df.AvgPopValue, Vnu);

            for (int i = 0; i < expCount; i++)

            {
            Matrix[] NuFull = GenerationUtils.GenerateNoise(groupCount, genPop.populations, Vnu, true);
            Matrix[] Nu = GenerationUtils.GenerateNoise(groupCount, genPop.populations, Vnu, fullind);
            Matrix[] MatrixNu = GenerationUtils.GenerateMatrixNoise(groupCount, genPop.populationMatrixes, Utf, Utm);

            x = df.Solve(NuFull, MatrixNu);
            xx = df.SolveWithFilter(Nu, MatrixNu);

            double sigma1 = DemogFilterAlg.CalcRelativelDeviation(genPop.populations[periodCount-1], x[periodCount-1], disp);
            double sigma2 = DemogFilterAlg.CalcRelativelDeviation(genPop.populations[periodCount-1], xx[periodCount-1], disp);

            s1 += sigma1;
            s2 += sigma2;

            }
            s1 /= expCount;
            s2 /= expCount;

            tbAccurate.Text = Math.Round(s1,5).ToString();
            tbEstimate.Text = Math.Round(s2, 5).ToString();
        }



    }
}
